package cn.maihe.elg.operation.service.system.impl;

import cn.hutool.core.lang.Assert;
import cn.maihe.elg.operation.common.Constants;
import cn.maihe.elg.operation.exception.ErrorCode;
import cn.maihe.elg.operation.exception.SystemRuntimeException;
import cn.maihe.elg.operation.model.enums.UserStatusEnum;
import cn.maihe.elg.operation.model.vo.system.SendSmsRespDTO;
import cn.maihe.elg.operation.repository.entity.*;
import cn.maihe.elg.operation.repository.entity.entityCustom.RoleDOCustom;
import cn.maihe.elg.operation.repository.entity.entityCustom.UserDOCustom;
import cn.maihe.elg.operation.repository.mapper.RoleMapper;
import cn.maihe.elg.operation.repository.mapper.UserMapper;
import cn.maihe.elg.operation.repository.mapper.UserRoleMapper;
import cn.maihe.elg.operation.security.model.UserContext;
import cn.maihe.elg.operation.service.BaseDaoService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.system.SmsService;
import cn.maihe.elg.operation.service.system.UserService;
import cn.maihe.elg.operation.utils.DateUtil;
import cn.maihe.elg.operation.utils.HttpsClientRequestFactory;
import cn.maihe.elg.operation.utils.IdGenerate;
import cn.maihe.elg.operation.utils.Sha256;
import cn.maihe.framework.starter.mybatis.dao.MybatisDaoImpl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author JHWei
 * @date 2018/3/18
 */
@Service
@Slf4j
public class UserServiceImpl extends BaseDaoService<UserDO> implements UserService {
    Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private SmsService smsService;
    @Value("${allowFailedTimes}")
    private int allowFailedTimes;

    @Value("${lockInterval}")
    private int lockInterval;

    private RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());

    @Override
    public UserDOCustom getByUsername(String username) {
//        List<UserDOCustom> userList = userMapper.findByUsername(username);

        Map<String, Object> paramMap = new HashMap<>(8);
        paramMap.put("username", username);
        List<UserDOCustom> userList = MybatisDaoImpl.of(UserMapper.class).selectListBySql("findByUsername", paramMap);

        for (UserDOCustom user : userList) {
            List ro = roleMapper.findByUserId(user.getId());
            user.setRoleList(ro);
        }
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        List<UserDOCustom> newUserList = new ArrayList<>();
        for (UserDOCustom user : userList) {
            if (!user.getStatus().equals(UserStatusEnum.DELETED.name())) {
                newUserList.add(user);
            }
        }
        if (CollectionUtils.isEmpty(newUserList)) {
            return null;
        }
        return userList.get(0);
    }

    //
    @Override
    public PageInfo<UserDOCustom> getUsersDoPage(String username, String name, Integer type, int pageNum, int pageSize, String status, String orgCode) {

        return new PageInfo<>(PageHelper.startPage(pageNum, pageSize).doSelectPage(() -> userMapper.findByUsernameLikeOrNameLike(username, name, status, orgCode, type)));
    }

    @Override
    public UserDOCustom getUser(Long id) {
        UserDOCustom userDO = userMapper.selectByIdCustom(id);
        if (StringUtils.isEmpty(userDO.getFullName())) {
            userDO.setFullName("");
        } else {
            userDO.setFullName(userDO.getFullName() + "(" + userDO.getOrgCode() + ")");
        }
        userDO.setRoleList(roleMapper.findByUserId(id));
        return userDO;
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public void saveUser(UserDOCustom user) {
        if (user == null) {
            return;
        }
        // 判断登录账号和状态判断是否重复
        Integer countUserName = userMapper.selectCount(new EntityWrapper<UserDO>()
                .eq("username", user.getUsername())
                .ne("status", UserStatusEnum.DELETED.toString()));
        if (countUserName > 0) {
            log.error("创建用户失败， 登录账号重复");
            throw new SystemRuntimeException(ErrorCode.BSMUM001, user.getUsername());
        }
        // 判断姓名和状态判断是否重复
        Integer countName = userMapper.selectCount(new EntityWrapper<UserDO>()
                .eq("name", user.getName())
                .ne("status", UserStatusEnum.DELETED.toString()));
        if (countName > 0) {
            log.error("创建用户失败， 姓名重复");
            throw new SystemRuntimeException(ErrorCode.BSMUM001, user.getName());
        }
        Date current = new Date();
        try {
            user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
            user.setPwdExpiredTime(DateUtil.getDayAfter(90));
            user.setGmtCreate(current);
            user.setGmtModified(current);
            user.setUserCreate(this.getUserContext().getUsername());
            user.setUserModified(this.getUserContext().getUsername());
            user.setStatus(UserStatusEnum.NORMAL.toString());
            user.setId(IdGenerate.getId());
            userMapper.insert(user);
        } catch (Exception e) {
            logger.error(e.toString());
            throw new SystemRuntimeException(ErrorCode.BSMSC008);
        }
        List<RoleDOCustom> roleList = user.getRoleList();
        if (CollectionUtils.isEmpty(roleList)) {
            log.error("请添加用户角色");
            throw new SystemRuntimeException(ErrorCode.BSMUM002);
        }
        insertUseRole(user, user);
    }

    @Override
    public void updateUserInfo(UserDOCustom user) {
        if (user == null) {
            return;
        }
        List<UserDO> existUser = userMapper.selectList(new EntityWrapper<UserDO>()
                .eq("username", user.getUsername())
                .ne("status", UserStatusEnum.DELETED.toString())
                .orderDesc(Arrays.asList(new String[]{"gmt_modified"}))
        );
        if (CollectionUtils.isEmpty(existUser)) {
            log.error("用户不存在");
            throw new SystemRuntimeException(ErrorCode.BSMUM003, user.getUsername());
        }
        UserDO userDb = userMapper.selectById(user.getId());

        if (userDb == null) {
            return;
        }
        userDb.setEmail(user.getEmail());
        userDb.setMobileNo(user.getMobileNo());
        userDb.setGmtModified(new Date());
        userDb.setUserModified(this.getUserContext().getUsername());
        userMapper.updateById(userDb);

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public void updateUser(UserDOCustom user) {
        if (user == null) {
            return;
        }
        List<UserDO> existUser = userMapper.selectList(new EntityWrapper<UserDO>()
                .eq("username", user.getUsername())
                .ne("status", UserStatusEnum.DELETED.toString())
                .orderDesc(Arrays.asList(new String[]{"gmt_modified"}))
        );
        if (CollectionUtils.isEmpty(existUser)) {
            log.error("用户不存在");
            throw new SystemRuntimeException(ErrorCode.BSMUM003, user.getUsername());
        }
        List<RoleDOCustom> roleList = user.getRoleList();
        if (CollectionUtils.isEmpty(roleList)) {
            log.error("请添加用户角色");
            throw new SystemRuntimeException(ErrorCode.BSMUM002);
        }

        UserDO userDb = userMapper.selectById(user.getId());

        if (userDb == null) {
            return;
        }
        userDb.setEmail(user.getEmail());
        userDb.setMobileNo(user.getMobileNo());
        userDb.setName(user.getName());
        userDb.setOrgId(user.getOrgId());
        userDb.setGmtModified(new Date());
        userDb.setUserModified(this.getUserContext().getUsername());
        userMapper.updateById(userDb);
        // 更新角色
        // 删除原有角色
        userRoleMapper.delete(new EntityWrapper<UserRoleDO>()
                .eq("user_id", userDb.getId()));
        // 插入新角色
        insertUseRole(user, userDb);
    }

    private void insertUseRole(UserDOCustom user, UserDO userDb) {
        List<RoleDOCustom> roles = user.getRoleList();
        List<Long> roleIds = new ArrayList<>();
        //roles.stream().map(RoleDO::getId).collect(Collectors.toList());
        for (RoleDO roleDO : roles) {
            roleIds.add(roleDO.getId());
        }
        userMapper.insertUserRoles(roleIds, userDb.getId());
    }

    @Override
    @Transactional
    public void deleteUser(Long id) {
        userRoleMapper.delete(new EntityWrapper<UserRoleDO>()
                .eq("user_id", id));
        userMapper.deleteById(id);
    }

    //param.get("username"), param.get("rawpassword"), param.get("password")
    @Override
    public void changePassword(Map<String, String> param) {
        if (param == null
                || param.get("username") == null
                || param.get("rawpassword") == null
                || param.get("password") == null) {
            throw new SystemRuntimeException(ErrorCode.BSMCM001);
        }
        String username = param.get("username");
        String rawpassword = param.get("rawpassword");
        String password = param.get("password");
        List<UserDO> userList = userMapper.selectList(new EntityWrapper<UserDO>()
                .eq("username", username)
                .eq("status", UserStatusEnum.NORMAL.toString())
                .orderDesc(Arrays.asList(new String[]{"gmt_modified"}))
        );
        if (CollectionUtils.isEmpty(userList)) {
            log.error("用户不存在");
            throw new SystemRuntimeException(ErrorCode.BSMUM003, username);
        }
        UserDO user = userList.get(0);
        if (!new BCryptPasswordEncoder().matches(rawpassword, user.getPassword())) {
            log.error("原密码输入错误");
            throw new SystemRuntimeException(ErrorCode.BSMUM004);
        }
        try {
            user.setPassword(new BCryptPasswordEncoder().encode(password));
            Date nowDate = new Date();
            UserDO updateUser = new UserDO();
            updateUser.setPassword(user.getPassword());
            updateUser.setId(user.getId());
            updateUser.setGmtModified(nowDate);
            updateUser.setUserModified(this.getUserContext().getUsername());
            updateUser.setPwdExpiredTime(DateUtil.getDayAfter(90));
            userMapper.updateById(updateUser);
        } catch (Exception e) {
            logger.error(e.toString());
            throw new SystemRuntimeException(ErrorCode.BSMSC007);
        }
    }

    @Override
    public void resetPassword(Long id, String password) {
        if (id == null || StringUtils.isEmpty(password)) {
            log.error("入参不可为空");
            throw new SystemRuntimeException(ErrorCode.BSMUM005);
        }
        UserDO user = userMapper.selectById(id);
        if (user == null) {
            log.error("用户不存在");
            throw new SystemRuntimeException(ErrorCode.BSMUM003);
        }
        try {
            user.setPassword(new BCryptPasswordEncoder().encode(password));
            Date nowDate = new Date();
            UserDO updateUser = new UserDO();
            updateUser.setPassword(user.getPassword());
            updateUser.setId(user.getId());
            updateUser.setGmtModified(nowDate);
            updateUser.setUserModified(this.getUserContext().getUsername());
            userMapper.updateById(updateUser);
        } catch (Exception e) {
            logger.error(e.toString());
            throw new SystemRuntimeException(ErrorCode.BSMSC006, "密码修改失败");
        }

    }

    @Override
    public boolean isUserLocked(UserDO user) {
        if (user == null) {
            return false;
        }
        if (user.getStatus().equals(UserStatusEnum.LOCKED.name())) {
            Date lastLockedTime = user.getLastLockedTime();
            Date now = new Date();
            int millisecond = 1000;
            if ((now.getTime() - lastLockedTime.getTime()) >= (lockInterval * millisecond)) {
                unLock(user);
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    @Override
    public void loginError(UserDO user) {

        if (user == null) {
            return;
        }

        if (user.getStatus().equals(UserStatusEnum.LOCKED.name())) {
            return;
        }

        int loginFailTimes = (user.getLoginFailTimes() == null ? 0 : user.getLoginFailTimes());

        if (loginFailTimes >= allowFailedTimes) {
            return;
        }

        user.setLoginFailTimes(++loginFailTimes);

        if (user.getLoginFailTimes() == allowFailedTimes) {
            user.setStatus(UserStatusEnum.LOCKED.name());
            user.setLastLockedTime(new Date());
        }
        userMapper.updateById(user);
    }

    @Override
    public void unLock(Long userId) {
        UserDO user = userMapper.selectById(userId);
        unLock(user);
    }

    @Override
    public void resetLoginFailTimes(Long userId, int loginCount) {
        UserDO userDO = new UserDO();
        userDO.setLoginFailTimes(0);
        userDO.setLastLockedTime(new Date());
        userDO.setLastLoginTime(new Date());
        userDO.setLoginCount(loginCount + 1);
        userDO.setId(userId);
        userMapper.updateById(userDO);

    }

    @Override
    public List<String> getUserPerm(Long userId) {
        return userMapper.findPermByUserId(userId);
    }

    @Override
    public UserContext getUserContext() {
        return (UserContext) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

    @Override
    public List<Long> getCenterIds(String userId) {
        return userMapper.getCenterIds(userId);
    }

    @Override
    public List<Long> getInstitutionIds(String userId) {
        return userMapper.getInstitutionIds(userId);
    }

    @Override
    public void saveOrUpdateBidUser(UserDO userDO) {
        Assert.notNull(userDO, "userNO不能为空");
        Assert.notNull(userDO.getUsername(), "登录账号不能为空");
        Assert.notNull(userDO.getOrgId(), "投标人单位信息不能为空");
        //userName存放统一社会信用代码
        UserDO user = MybatisDaoImpl.run().selectOne(UserDOCondition.builder()
                .andUsernameEq(userDO.getUsername()).andOrgIdEq(userDO.getOrgId()).build());
        if (user != null) {
            // todo:Alan取消投标企业账户区分交易中心id
//            if(userDO.getOrgId().longValue()!=user.getOrgId().longValue()){
//                throw new RuntimeException("社会信用代码已关联其他交易中心");
//            }
            user.setMobileNo(userDO.getMobileNo());
            user.setUsername(userDO.getUsername());
            user.setName(userDO.getName());
            user.setGmtModified(new Date());
            this.userMapper.updateById(user);
        } else {
//            //followId也是存放社会信用代码 与 userName一致
//            UserDO dbUser = MybatisDaoImpl.run().selectOne(UserDOCondition.builder()
//                    .andFollowIdEq(userDO.getFollowId()).build());
//            if (dbUser != null) {//update
//                dbUser.setMobileNo(userDO.getMobileNo());
//                dbUser.setUsername(userDO.getUsername());
//                dbUser.setName(userDO.getName());
//                dbUser.setGmtModified(new Date());
//                this.userMapper.updateById(dbUser);
//            } else {
                //add 默认投标人登录密码Constants.DEFAULT_BIDDER_PWD
                userDO.setId(IdGenerate.getId());
                userDO.setPassword(new BCryptPasswordEncoder().encode(Sha256.shaEncode(Constants.DEFAULT_BIDDER_PWD, userDO.getUsername())));
                userDO.setPwdExpiredTime(DateUtil.getDayAfter(90));
                userDO.setGmtCreate(new Date());
                userDO.setGmtModified(new Date());
                this.userMapper.insert(userDO);
//            }

        }
    }

    @Override
    public boolean checkOrder(Long orgId, String acceptOrderNo) {
        AcceptOrderInfoDO orderInfoDO = acceptOrderInfoService.getByAcceptOrderNo(acceptOrderNo);
        if (orderInfoDO == null) {
            return false;
        }
        return orgId.longValue() == orderInfoDO.getBidCustomerId();
    }

    @Override
    public boolean checkSmsCode(String username, String smsCode) {
        SendSmsRespDTO sendSmsRespDTO = smsService.checkSmsCode(username, smsCode);
        if (sendSmsRespDTO.getStatus().equals("SUC")) {
            return true;
        }
        return false;
    }

    private void unLock(UserDO user) {
        if (user == null) {
            throw new SystemRuntimeException(ErrorCode.BSMUM003);
        }
        if (!user.getStatus().equals(UserStatusEnum.LOCKED.name())) {
            return;
        }
        user.setStatus(UserStatusEnum.NORMAL.name());
        user.setLoginFailTimes(0);
        userMapper.updateById(user);
    }
}
